package monitor

import (
	"sync"
	"cloud_worm/worm/client/monitor/logcollector"
	"errors"
	"strings"
	"cloud_worm/worm/config"
	"github.com/golang/glog"
	"context"
	"cloud_worm/worm/client/monitor/monitorlog"
	"fmt"
	"io/ioutil"
	"cloud_worm/util/ufile"
	"cloud_worm/util/proto/ujson"
)

var logCollectorMutex 	sync.Mutex
var logCollector 		*logcollector.Watcher

func StartLogWatcher(localIP string) error {
	logCollectorMutex.Lock()
	defer logCollectorMutex.Unlock()

	if logCollector != nil {
		return errors.New("log watcher had started")
	}

	if strings.Contains(config.CfgInst.RunMode, "dev") {
		ctxW, _ := context.WithCancel(context.Background())

		// 测试环境，仅写日志，不写kafka
		watcher := logcollector.NewWatcher(ctxW, localIP, nil, monitorlog.MonLogFd)
		if watcher == nil {
			e := errors.New("new log watcher failed")
			PushMonitorErrInfo(e)
			return e
		}

		logCollector = watcher
	} else if strings.HasPrefix(localIP, "10.70.") == false && strings.HasPrefix(localIP, "10.13.") == false {
		// 必须保证kafka存在才启动
		ctxW, _ := context.WithCancel(context.Background())

		// 仅写kafka，不写日志，所以logFd设置为nil
		p, err := producerPool.Get(LogTopic)
		if err != nil {
			e := fmt.Errorf("get topic'%s' producer error", LogTopic)
			PushMonitorErrInfo(e)
			return e
		}
		watcher := logcollector.NewWatcher(ctxW, localIP, p, nil)
		if watcher == nil {
			producerPool.Put(LogTopic)
			e := errors.New("new log watcher failed")
			PushMonitorErrInfo(e)
			return e
		}

		logCollector = watcher
	}

	logcollector.LocalIP = localIP
	fileURL := fmt.Sprintf("%s/worm/worm/%s",
		config.CfgInst.StartConfig.(*config.ClientConfig).ServerSet.AutoConfigURL, ujson.LogCollectorRuleFile)
	if err := updateCollectorRuleWithoutLock(fileURL, "init"); err != nil {
		glog.Errorf("updateCollectorRuleWithoutLock: %s", err.Error())
		PushMonitorErrInfo(err)
	}
	glog.Info("start log watcher loop ....")
	return nil
}

func StopLogWatcher()  {
	logCollectorMutex.Lock()
	defer logCollectorMutex.Unlock()

	if logCollector == nil {
		return
	}

	producerPool.Put(LogTopic)
	logCollector.Close()
	logCollector = nil
	return
}

func init()  {
	logCollector = nil
}

// 更新update collector rule的配置
func UpdateCollectorRule(fileURL string, md5 string) error {
	logCollectorMutex.Lock()
	defer logCollectorMutex.Unlock()

	if logCollector == nil {
		return nil
	}

	destFile := "./var/" + ujson.LogCollectorRuleFile
	oldMD5 := ufile.GetFileMd5(destFile)
	if oldMD5 == md5 {
		return nil
	}

	if err := ufile.DownloadFile(fileURL, destFile); err != nil {
		glog.Errorf("download file'%s' error: %s", ujson.LogCollectorRuleFile, err.Error())
		PushMonitorErrInfo(err)
		return err
	}

	data, err := ioutil.ReadFile(destFile)
	if err != nil {
		return err
	}
	if strings.Contains(string(data), ujson.Page404NotFound) {
		e := fmt.Errorf("url: %s, 404 page not found", fileURL)
		PushMonitorErrInfo(e)
		return e
	}
	tmp := strings.Split(string(data), "\n")

	cs := make([]*logcollector.CollectorObj, 0, len(tmp))
	for _, item := range tmp {
		f := strings.Split(item, "|")
		if len(f) == 2 {
			fileName := strings.TrimSpace(f[0])
			parser := strings.TrimSpace(f[1])
			if fileName == "" {
				continue
			}
			if parser == "" {
				parser = ujson.DefaultParserName
			}

			c := &logcollector.CollectorObj{
				FileName: fileName,
				Parser: parser,
			}
			cs = append(cs, c)
		}
	}

	for _, item := range cs {
		glog.Infof("%s:%s\n", item.FileName, item.Parser)
	}
	if errs := logCollector.UpdateCollectorRule(cs); errs != nil {
		for _, err := range errs {
			PushMonitorErrInfo(err)
		}
	}
	return nil
}

// 更新update collector rule的配置
func updateCollectorRuleWithoutLock(fileURL string, md5 string) error {

	if logCollector == nil {
		return nil
	}

	destFile := "./var/" + ujson.LogCollectorRuleFile
	oldMD5 := ufile.GetFileMd5(destFile)
	if oldMD5 == md5 {
		return nil
	}

	if err := ufile.DownloadFile(fileURL, destFile); err != nil {
		glog.Errorf("download file'%s' error: %s", ujson.LogCollectorRuleFile, err.Error())
		PushMonitorErrInfo(err)
		return err
	}

	data, err := ioutil.ReadFile(destFile)
	if err != nil {
		return err
	}
	if strings.Contains(string(data), ujson.Page404NotFound) {
		e := fmt.Errorf("url: %s, 404 page not found", fileURL)
		PushMonitorErrInfo(e)
		return e
	}
	tmp := strings.Split(string(data), "\n")

	cs := make([]*logcollector.CollectorObj, 0, len(tmp))
	for _, item := range tmp {
		f := strings.Split(item, "|")
		if len(f) == 2 {
			fileName := strings.TrimSpace(f[0])
			parser := strings.TrimSpace(f[1])
			if fileName == "" {
				continue
			}
			if parser == "" {
				parser = ujson.DefaultParserName
			}

			c := &logcollector.CollectorObj{
				FileName: fileName,
				Parser: parser,
			}
			cs = append(cs, c)
		}
	}

	for _, item := range cs {
		glog.Infof("%s:%s\n", item.FileName, item.Parser)
	}
	if errs := logCollector.UpdateCollectorRule(cs); errs != nil {
		for _, err := range errs {
			PushMonitorErrInfo(err)
		}
	}
	return nil
}